﻿import re




deviceInfo = {
    0x82: (';' , 10),
    0x90: ('M' , 10),
    0x91: ('SM', 10),
    0x92: ('L' , 10),
    0x94: ('V' , 10),
    0x9C: ('X' , 16),
    0x9D: ('Y' , 16),
    0x9E: ('FX', 16),
    0x9F: ('FY', 16),
    0xA0: ('B' , 16),
    0xA2: ('DX', 16),
    0xA3: ('DY', 16),
    0xA8: ('D' , 10),
    0xA9: ('SD', 10),
    0xAA: ('FD', 10),
    0xAB: ('G' , 10),
    0xAF: ('R' , 10),
    0xB4: ('W' , 16),
    0xC2: ('T' , 10),
    0xC5: ('C' , 10),
    0xCC: ('Z' , 10),
    0xCD: ('V' , 10),
    0xD0: ('P' , 10),
    0xD2: ('N' , 10),
    0xD8: ('U' , 16),
    0xD9: ('J' , 10),
    0xE8: ('K' , 10),
    0xE9: ('K' , 10),
    0xEA: ('H' , 16),
    0xEB: ('H' , 16),
    0xEE: ('"' , 10),
    0xF0: ('Z' , 10),
    0xF1: ('K' , 10),
    0xF2: ('.' , 10),
    0xF3: ('@' , 10),
    0xF4: ('V' , 10),
    0xF8: ('U' , 16),
    0xF9: ('J' , 10)}    
    

# 확장코드: 주가 되는 디바이스의 앞/뒤에 붙혀 디바이스의 의미를 확장시켜주는 코드
# 확장코드는 0xF0 이상의 값을 가진다. 따라서 deviceInfo 에서 정보를 얻을 수 있다.
extcode = {}
maincode = {}
def mapextcode(item):
    key, (name, base) = item
    if key < 0xF0:
        maincode[name] = (key, base)
    else:
        extcode[name] = (key, base)
map(mapextcode, deviceInfo.items())

address = {'dec':'[0-9]+', 'hex':'[0-9A-F]+'}
device_re = re.compile('(%(prefix)s)?(%(main)s)(%(postfix)s)?' % {
    'prefix': '(K)([1-8])|(J)(%(dec)s)[\\/]|(U)(%(hex)s)[\\/]|(@)' % address,
    'main': '([MLDRTC]|SM|SD)(%(dec)s)|([XYBW]|DX|DY)(%(hex)s)' % address,
    'postfix': '([ZV])(%(dec)s)|(\\.)(%(hex)s)' % address,
    })

def getcode(table, device):
    name, address = device
    code, base = table[name]
    return code, int(address, base)

class GxDevice:

    def __init__(self, device, command):
        self.command = command
        self.parse(device)
        command.append(self)

    def code(self):
        codes = []
        if self.prefix:
            codes.append(getcode(extcode, self.prefix))
        if self.postfix:
            codes.append(getcode(extcode, self.postfix))
        if self.main:
            codes.append(getcode(maincode, self.main))
        return codes

    def format(self, stream):
        for device in self.code():
            if 256 <= device[1]:
                device = device[0], device[1] % 256, device[1] / 256
            stream.writecode(device)

    def __repr__(self):
        return 'Device: %s' % (repr((self.prefix, self.main, self.postfix)))

    # choice
    def choice(self, list):
        it = iter(list)
        for i in it:
            if i != None:
                try:
                    next = it.next()
                except StopIteration:
                    next = '0'
                return i, next

    def parse(self, device):
        g = device_re.match(device).groups()
        # index는 device_re에 포함된 ()의 수에 의한 것이다.
        # device_re가 변하면 index도 변해야 한다.
        prefix = 0
        main = 8
        postfix = 13
        if g[prefix] != None:
            self.prefix = self.choice(g[prefix+1:main])
        else:
            self.prefix = None
        if g[main] != None:
            self.main = self.choice(g[main+1:postfix])
        else:
            self.main = None
        if g[postfix] != None:
            self.postfix = self.choice(g[postfix+1:])
        else:
            self.postfix = None

def parse(device, command):
    return GxDevice(device, command)

def code2name(code, no):
    try:
        name, base = deviceInfo[code]
    except KeyError:
        name = "//%02X//" % code
        base = 16
    return (base == 10 and "%s%d" or "%s%X") % (name, no)

print code2name(0x100, 0)

class GxDevice(gx.GxObject):
    def __init__(self, codes):
        self.codes = codes

    def __repr__(self):
        return "<%s:'%s'>" % (self.__class__.__name__, self.__str__())

    def __str__(self):
        pre = []
        main = []
        post = []
        for code in self.codes:
            try:
                name, address = _getname(code)
                if code[0] == 0x82:
                    main.append(";" + address)
                elif code[0] == 0xEE:
                    main.append('"' + address + '"')
                elif code[0] >= 0xF0: # 확장
                    if name in "UJ":
                        pre.append(name + address + "\\")
                    elif name == "K":
                        pre.append(name + address)
                    elif name == "@":
                        pre.append(name)
                    elif name in "ZV.":
                        post.append(name + address)
                else:
                    main.append(name + address)
            except KeyError:
                main.append("%02X:%d" % (code[0], code[1][0]))
        return "".join(pre + main + post)

    @staticmethod
    def fromCode(stream):
        codes = [stream.getNextDevice()]
        while codes[-1][0] >= 0xF0 and stream.nextIsDevice():
            codes.append(stream.getNextDevice())
        return GxDevice(codes)
